package com.qk.service.impl;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.qk.common.PageResult;
import com.qk.dto.UserDto;
import com.qk.entity.User;
import com.qk.exception.BusinessException;
import com.qk.mapper.UserMapper;
import com.qk.service.UserService;
import com.qk.utils.JwtUtils;
import com.qk.vo.LoginResultVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    // 用户列表查询——————展示用户列表
    @Override
    public PageResult<User> list(UserDto userDto) {
        //1. 设置分页参数
        PageHelper.startPage(userDto.getPage(), userDto.getPageSize());

        //2. 调用mapper接口查询
        List<User> userList = userMapper.selectList(userDto);
        //查询结果封装到User对象中，而User对象中没有【部门名称】【角色名称】     所以我们会在User中【扩展属性】，另外添加上：见User.java

        //3. 解析并封装结果
        Page<User> page = (Page<User>) userList;    // 强转为【Page】：目的：为了调用Page的方法
        return new PageResult<>(page.getTotal(), page.getResult());
    }
    /*
        1. 【PageResult的作用】：这是一个通用的分页结果封装类，【用于封装分页查询的结果，包括总记录数和当前页的数据列表】
        2. 【封装为PageResult的原因】：在分页查询中，将查询结果和分页信息（总记录数、当前页数据）统一封装返回，便于前端处理分页展示
        3. 【参数分析】：第一个参数: page.getTotal() - 获取总记录数
                      第二个参数: page.getResult() - 获取当前页的数据结果集
        4. 【泛型类型】由于在UserService中定义了返回类型为 PageResult<User>，所以这里的 PageResult<> 会自动推断为 PageResult<User>
    表示这个分页结果是专门用于封装 User 对象的
     */


    // 新增用户
    @Override
    public void add(User user) {
        // 1. 补全基础属性
        user.setCreateTime(LocalDateTime.now());    // 前端传来的缺少这两个默认必要数据，所以这里在service层，单独添加
        user.setUpdateTime(LocalDateTime.now());

        // 2. 设置默认密码                                // 不设置默认密码不行：因为数据库中，密码字段！=null
        String password = user.getUsername() + "123";  // 新增用户时，没有让设置密码，所以这里在service层统一设置默认密码：password + 123*/
        user.setPassword(DigestUtils.md5DigestAsHex(password.getBytes()));
        // 【MD5加密】：信息摘要算法，一种被广泛使用的密码散列函数，可以产生一个128位(16字节)的散列值，通常用于登录密码加密处理(只能加密，不能解密)
        /*
        在 Spring 框架中，提供的有一个 DigestUtils 工具类，主要用于对字符串进行 MD5 加密，并返回加密后的结果。
          *  md5DigestAsHex(byte[] bytes)：  将指定字节数组的值，转为经过 MD5 加密后的字符串
          * .getBytes()：                    将密码转为字节数组
        */

        // 3. 调用mapper，插入数据
        userMapper.insert(user);
    }



    @Override
    public LoginResultVo login(User user) {
        //1. 调用Mapper接口查询用户
        User u = userMapper.selectByUsername(user.getUsername());
        //2. 判断用户是否存在
        if (u == null){ // 用户不存在
            log.info("用户不存在");
            throw new BusinessException("用户名或密码错误");
        }
        //3. 判断用户密码是否正确
        String _pass = DigestUtils.md5DigestAsHex(user.getPassword().getBytes());
        if(!_pass.equals(u.getPassword())){
            log.info("用户密码错误");
            throw new BusinessException("用户名或密码错误");
        }
        //4. 判断状态是否正确
        if(u.getStatus() != 1){
            log.info("用户已停用");
            throw new BusinessException("用户已停用");
        }
        //5. 封装结果并返回
        LoginResultVo loginResultVo = new LoginResultVo();
        loginResultVo.setId(u.getId());
        loginResultVo.setUsername(u.getUsername());
        loginResultVo.setName(u.getName());
        loginResultVo.setImage(u.getImage());
        loginResultVo.setRoleLabel(u.getRoleLabel());

        //调用工具类, 生成jwt令牌
        Map<String, Object> claims = new HashMap<>();
        claims.put("id", u.getId());
        claims.put("username", u.getUsername());
        String jwt = JwtUtils.generateToken(claims);

        loginResultVo.setToken(jwt);

        return loginResultVo;
    }

}
